package myJs.cultivars.silico

import myJs.api.Api
import myJs.cps.{Display, Style}
import myJs.myPkg.d3.d3T
import myJs.myPkg.jquery.$
import myJs.myPkg.{PhyTreeNode, Phylotree, PhylotreeOptions, layer}
import myJs.tool.Tool
import slinky.core.FunctionalComponent
import slinky.core.annotations.react
import slinky.core.facade.Hooks.useEffect
import slinky.web.html._
import myJs.Implicits._
import org.scalajs.dom.document
import org.scalajs.dom.html.Div

import scala.scalajs.js
import scala.scalajs.js.Dynamic.{global => g}
import org.scalajs.macrotaskexecutor.MacrotaskExecutor.Implicits._
import slinky.core.facade.React

/**
 * Created by yz on 3/11/2020
 */
@react object PhyloCp {

  case class Props()

  var tree: Phylotree = _

  val divRef = React.createRef[Div]

  val component = FunctionalComponent[Props] { props =>

    object FTool {

      def layout(kind: String) = () => {
        kind match {
          case "linear" =>
            if (tree.radial()) {
              tree.radial(false).placenodes().update()
            }
          case "radial" =>
            if (!tree.radial()) {
              tree.radial(true).placenodes().update()
            }
        }
        ()
      }

      def align(kind: String) = () => {
        kind match {
          case "right" =>
            if (tree.align_tips(true).isDdefined) {
              tree.placenodes.placenodes().update()
            }
          case "left" =>
            if (tree.align_tips(false).isDdefined) {
              tree.placenodes.placenodes().update()
            }
        }
        ()
      }

      def spacingChange(direction: String, amount: Int) = () => {
        direction match {
          case "vertical" =>
            tree.spacing_x(tree.spacing_x() + amount).update()
          case "horizontal" =>
            tree.spacing_y(tree.spacing_y() + amount).update()
        }
        ()
      }

      def sortNodes(asc: Boolean) = () => {
        tree.traverse_and_compute((n: PhyTreeNode) => {
          val maxCountDepth = if (n.children.isDdefined && n.children.size > 0) {
            n.children.map(_.count_depth).max
          } else 0
          n.count_depth = 1 + maxCountDepth
        })
        tree.resort_children((a: PhyTreeNode, b: PhyTreeNode) => {
          val diff = a.count_depth - b.count_depth
          if (asc) diff else -(diff)
        })
        ()
      }

      def restoreSort = () => {
        tree.resort_children((a: PhyTreeNode, b: PhyTreeNode) => {
          a.original_child_order - b.original_child_order
        })
        ()
      }

      def submitBefore = () => {
        val html = $(divRef.current).find("svg:first").outerHTMLSome
        $(divRef.current).findInputByName("svgHtml").`val`(html)
        ()
      }

      def refreshTree = {
        val index = layer.load(1, Tool.layerOptions.copy(shade = List("0.1", "#fff")))
        Api.nwkData("silicoDArT.nwk").map { response =>
          val containerId = "tree_container"
          val d3 = g.d3.asInstanceOf[d3T]
          val nwk = response
          val svgE = d3.select($(divRef.current).find(s"#${containerId}")(0))
          tree = Phylotree().svg(svgE).radial(false).spacing_x(12, true).
            spacing_y(20, true)
          tree = tree(nwk).layout()
          layer.close(index)
        }

      }

    }

    useEffect(() => {
      FTool.refreshTree
    }, List()
    )

    div(
      div(style := Style(border = "1px solid #ccc"), ref := divRef,
        div(
          div(className := "btn-group myGroup",
            button(className := "btn btn-default btn-sm",
              title := "Expand vertical spacing", onClick := FTool.spacingChange("vertical", 1),
              i(className := "fa fa-arrows-v")
            ),
            button(className := "btn btn-default btn-sm",
              title := "Compress vertical spacing", onClick := FTool.spacingChange("vertical", -1),
              i(className := "fa  fa-compress fa-rotate-135")
            ),
            button(className := "btn btn-default btn-sm",
              title := "Expand horizonal spacing", onClick := FTool.spacingChange("horizontal", 1),
              i(className := "fa fa-arrows-h")
            ),
            button(className := "btn btn-default btn-sm",
              title := "Compress horizonal spacing", onClick := FTool.spacingChange("horizontal", -1),
              i(className := "fa  fa-compress fa-rotate-45")
            ),
            button(className := "btn btn-default btn-sm", onClick := FTool.sortNodes(true),
              title := "Sort deepest clades to the bototm",
              i(className := "fa fa-sort-amount-asc")
            ),
            button(className := "btn btn-default btn-sm", onClick := FTool.sortNodes(false),
              title := "Sort deepsest clades to the top",
              i(className := "fa fa-sort-amount-desc")
            ),
            button(className := "btn btn-default btn-sm", onClick := FTool.restoreSort,
              title := "Restore original order",
              i(className := "fa fa-sort")
            )
          ),
          " ",
          div(className := "btn-group", style := Style(marginTop = "15px"),
            form(className := "myForm", action := s"${Api.apiUrl}/nut/downloadTree", method := "post",
              style := Style(display = Display.inline), onSubmit := FTool.submitBefore,
              input(`type` := "hidden", name := "svgHtml"),
              button(className := "btn btn-default btn-sm", `type` := "submit", data - "direction" := "horizontal",
                title := "Save image",
                i(className := "fa fa-picture-o")
              ),
            )
          ),

          div(className := "btn-group myGroup", data - "toggle" := "buttons",
            label(className := "btn btn-default btn-sm active", onClick := FTool.layout("linear"),
              input(name := "options", className := "phylotree-layout-mode", autoComplete := "off",
                title := "Layout left-to-right", `type` := "radio",
                style := Style(width = "100%")
              ),
              "Linear"
            ),
            label(className := "btn btn-default btn-sm", onClick := FTool.layout("radial"),
              input(name := "options", className := "phylotree-layout-mode", autoComplete := "off",
                title := "Layout radially", `type` := "radio"
              ),
              "Radial"
            )
          ),

          div(className := "btn-group myGroup", data - "toggle" := "buttons",
            label(className := "btn btn-default btn-sm active", onClick := FTool.align("left"),
              input(name := "options-align", className := "phylotree-align-toggler", autoComplete := "off", checked := true,
                title := "Align tips labels to branches", `type` := "radio",
              ),
              i(className := "fa fa-align-left")
            ),
            label(className := "btn btn-default btn-sm", onClick := FTool.align("right"),
              input(name := "options-align", className := "phylotree-align-toggler", autoComplete := "off", data - "mode" := "radial",
                title := "Align tips labels to the edge of the plot", `type` := "radio",
              ),
              i(className := "fa fa-align-right")
            )
          ),

        ),
        {
          import slinky.web.svg._
          svg(id := "tree_container", className := "tree-widget", style := js.Dynamic.literal(width = "100%"))
        }

      )

    )

  }

}
